﻿#region

using System.Linq.Expressions;
using Mapster;
using SqlSugar;
using Vin.Extension.Framework.Dto;
using Vin.Extension.Framework.Entities;
using Vin.Extension.Framework.SugarFilter;
using Vin.Extension.JwtBearer.Models;
using Vin.Extension.JwtBearer.Tool;
using Vin.Extension.SqlSugar.Repository;
using Vin.Tool.Domain.ExceptionModel;

#endregion

namespace Vin.Extension.Framework.Repository;

public class VinFrameworkBaseRepository<TEntity> : VinBaseLogicRepository<TEntity>, IVinFrameworkBaseRepository<TEntity>
    where TEntity : VinFrameworkBaseEntity, new()
{
    #region Context设置

    public virtual Expressionable<TEntity> CreateExpressionable(
        Expression<Func<TEntity, bool>>? expression = null)
    {
        return Expressionable.Create<TEntity>()
            .AndIF(expression != null, expression);
    }

    public void AddEnabledFilter()
    {
        Context.QueryFilter.AddTableFilter<IEnabled>(m => m.IsEnabled == true);
    }
    
    public ISugarQueryable<TEntity> ClearTableFilterQueryable<T>()
    {
        return AsQueryable().ClearFilter<T>();
    }

    public ISugarQueryable<TEntity> ClearTableFilterQueryable<T, T2>()
    {
        return AsQueryable().ClearFilter<T, T2>();
    }

    public ISugarQueryable<TEntity> ClearTableFilterQueryable<T, T2, T3>()
    {
        return AsQueryable().ClearFilter<T, T2, T3>();
    }
    
    public ISugarQueryable<TEntity> ClearTableFilterQueryable(params Type[] types)
    {
        return AsQueryable().ClearFilter(types);
    }

    public void ClearTableFilter<T>()
    {
        Context.QueryFilter.Clear<T>();
    }
    
    
    public void ClearTableFilter<T,T2>()
    {
        Context.QueryFilter.Clear<T>();
        Context.QueryFilter.Clear<T2>();
    }
    
    public void ClearTableFilter<T,T2,T3>()
    {
        Context.QueryFilter.Clear<T>();
        Context.QueryFilter.Clear<T2>();
        Context.QueryFilter.Clear<T3>();
    }
    
    public void ClearTableFilter<T, T2, T3, T4>()
    {
        Context.QueryFilter.Clear<T>();
        Context.QueryFilter.Clear<T2>();
        Context.QueryFilter.Clear<T3>();
        Context.QueryFilter.Clear<T4>();
    }
    
    public void ClearTableFilter<T, T2, T3, T4, T5>()
    {
        Context.QueryFilter.Clear<T>();
        Context.QueryFilter.Clear<T2>();
        Context.QueryFilter.Clear<T3>();
        Context.QueryFilter.Clear<T4>();
        Context.QueryFilter.Clear<T5>();
    }

    public void ClearAllTableFilter()
    {
        Context.QueryFilter.Clear();
    }

    #endregion

    #region 获取Token授权信息

    public VinJwtTokenModel? GetTokenModel()
    {
        return VinSecurityTool.GetTokenModelByToken();
    }

    public T? GetTokenModel<T>() where T : VinJwtTokenModel
    {
        return VinSecurityTool.GetTokenModelByToken<T>();
    }

    #endregion

    #region 查询

    public async Task<List<TEntity>> QueryList(Expression<Func<TEntity, bool>>? whereExpression = null) =>
        whereExpression == null ? await GetListAsync() : await GetListAsync(whereExpression);

    public async Task<List<TEntity>> QueryList(bool enabledFilter,
        Expression<Func<TEntity, bool>>? whereExpression = null)
    {
        if (enabledFilter) AddEnabledFilter();
        return await QueryList(whereExpression);
    }

    /// <summary>
    /// 根据ID获取实体
    /// </summary>
    public async Task<TEntity> QueryEntityByIdAsync(long? id, string errorMsg = "数据不存在")
    {
        var entity = await base.GetByIdAsync(id);
        if (entity == null) throw new BusinessException(errorMsg);
        return entity;
    }

    public async Task<List<TEntity>> QueryByIdsAsync(List<long> ids)
    {
        return await AsQueryable().In(ids).ToListAsync();
    }

    #endregion

    #region 保存或更新

    public override IUpdateable<TEntity> Updateable(TEntity entity, Expression<Func<TEntity, bool>> whereExpression,
        bool ignoreAllNullColumns = true)
    {
        SetOperateInfo(entity);
        return base.Updateable(entity, whereExpression, ignoreAllNullColumns);
    }

    /// <summary>
    /// 设置操作人信息
    /// </summary>
    /// <param name="entity"></param>
    public void SetOperateInfo(TEntity entity)
    {
        var tokenModel = GetTokenModel();
        if (tokenModel == null)
        {
            entity.Id ??= GetNextId();
            return;
        }

        if (entity.Id == null)
        {
            entity.Id = GetNextId();
            entity.CreateUserId = tokenModel.RealUserId;
            entity.CreateUserName = tokenModel.UserName;
        }
        else
        {
            entity.UpdateUserId = tokenModel.RealUserId;
            entity.UpdateUserName = tokenModel.UserName;
        }
    }

    /// <summary>
    /// 保存或更新
    /// </summary>
    /// <param name="entity"></param>
    /// <param name="insertCallback"></param>
    /// <param name="updateCallback"></param>
    /// <param name="isIgnoreNull">是否忽略空值</param>
    /// <returns></returns>
    public async Task<TEntity?> SaveOrUpdateAsync(TEntity entity, Func<TEntity, Task>? insertCallback,
        Func<TEntity, Task>? updateCallback = null,
        bool isIgnoreNull = true)
    {
        var tokenModel = GetTokenModel();

        if (!entity.Id.HasValue)
        {
            // 插入
            entity.Id = GetNextId();

            if (insertCallback != null) await insertCallback.Invoke(entity);

            if (tokenModel != null)
            {
                entity.CreateUserId = tokenModel.RealUserId;
                entity.CreateUserName = tokenModel.UserName;
                entity.CreateAccountId = tokenModel.RealAccountId;
                entity.CreateAccountName = tokenModel.AccountName;
            }

            return await AsInsertable(entity).IgnoreColumnsNull(isIgnoreNull).ExecuteCommandAsync() > 0 ? entity : null;
        }

        entity.UpdateTime = DateTime.Now;

        if (updateCallback != null) await updateCallback.Invoke(entity);

        if (tokenModel != null)
        {
            entity.UpdateUserId = tokenModel.RealUserId;
            entity.UpdateUserName = tokenModel.UserName;
            entity.UpdateAccountId = tokenModel.RealAccountId;
            entity.UpdateAccountName = tokenModel.AccountName;
        }

        return await AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: isIgnoreNull).ExecuteCommandAsync() > 0
            ? entity
            : null;
    }

    public async Task<TEntity?> SaveOrUpdateAsync(TEntity entity, bool isIgnoreNull = true)
    {
        return await SaveOrUpdateAsync(entity, null, null, isIgnoreNull);
    }


    public async Task<TEntity?> SaveOrUpdateAsync(TEntity entity, Func<SaveType, TEntity, Task>? saveCallback,
        bool isIgnoreNull = true)
    {
        return await SaveOrUpdateAsync(entity,
            async (insertData) =>
            {
                if (saveCallback != null)
                    await saveCallback.Invoke(SaveType.Insert, insertData);
            },
            async (updateData) =>
            {
                if (saveCallback != null)
                    await saveCallback.Invoke(SaveType.Update, updateData);
            }, isIgnoreNull);
    }

    public async Task<bool> InsertRangeAsync(List<TEntity> entities, bool isIgnoreNull)
    {
        var tokenModel = GetTokenModel();
        if (tokenModel != null)
        {
            entities.ForEach(entity =>
            {
                entity.CreateUserId = tokenModel.RealUserId;
                entity.CreateUserName = tokenModel.UserName;
                entity.CreateAccountId = tokenModel.RealAccountId;
                entity.CreateAccountName = tokenModel.AccountName;
            });
        }

        return await AsInsertable(entities).IgnoreColumnsNull(isIgnoreNull).ExecuteCommandAsync() > 0;
    }

    public async Task<bool> InsertAsync(TEntity entity, bool isIgnoreNull)
    {
        var tokenModel = GetTokenModel();
        if (tokenModel != null)
        {
            entity.CreateUserId = tokenModel.RealUserId;
            entity.CreateUserName = tokenModel.UserName;
            entity.CreateAccountId = tokenModel.RealAccountId;
            entity.CreateAccountName = tokenModel.AccountName;
        }

        return await AsInsertable(entity).IgnoreColumnsNull(isIgnoreNull).ExecuteCommandAsync() > 0;
    }

    #endregion

    #region 删除

    public async Task<bool> LogicDeleteAsync(long? id)
    {
        return await LogicDeleteAsync(m => m.Id == id);
    }

    #endregion

    #region 对比

    public (List<TEntity>, List<TEntity>, List<TEntity>) Compare(
        List<TEntity> newDtoList, List<TEntity> newList)
    {
        // 新增的
        var insertList = newDtoList.Where(m => !m.Id.HasValue).ToList();
        // 更新的
        var updateList = newList.Where(m => newDtoList.Any(n => n.Id == m.Id)).ToList();
        // 删除的
        var deleteList = newList.Where(m => newDtoList.All(n => n.Id != m.Id)).ToList();

        return (insertList, updateList, deleteList);
    }

    public (List<TEntityDto>, List<TEntity>, List<TEntity>) Compare<TEntityDto>(
        List<TEntityDto> newDtoList, List<TEntity> newList)
        where TEntityDto : VinFrameworkBaseEntityDto
    {
        // 新增的
        var insertList = newDtoList.Where(m => !m.Id.HasValue).ToList();
        // 更新的
        var updateList = newList.Where(m => newDtoList.Any(n => n.Id == m.Id)).ToList();
        // 删除的
        var deleteList = newList.Where(m => newDtoList.All(n => n.Id != m.Id)).ToList();

        return (insertList, updateList, deleteList);
    }

    #endregion
}

public class VinFrameworkBaseRecordRepository<TEntity> : VinBaseLogicRepository<TEntity>,
    IVinFrameworkBaseRecordRepository<TEntity>
    where TEntity : VinFrameworkBaseRecordEntity, new()
{
    #region Context设置

    public virtual Expressionable<TEntity> CreateExpressionable(
        Expression<Func<TEntity, bool>>? expression = null)
    {
        return Expressionable.Create<TEntity>()
            .AndIF(expression != null, expression);
    }

    public void AddEnabledFilter()
    {
        Context.QueryFilter.AddTableFilter<IEnabled>(m => m.IsEnabled == true);
    }

    public ISugarQueryable<TEntity> ClearTableFilterQueryable<T>()
    {
        return AsQueryable().ClearFilter<T>();
    }

    public ISugarQueryable<TEntity> ClearTableFilterQueryable<T, T2>()
    {
        return AsQueryable().ClearFilter<T, T2>();
    }

    public ISugarQueryable<TEntity> ClearTableFilterQueryable<T, T2, T3>()
    {
        return AsQueryable().ClearFilter<T, T2, T3>();
    }
    
    public ISugarQueryable<TEntity> ClearTableFilterQueryable(params Type[] types)
    {
        return AsQueryable().ClearFilter(types);
    }

    /// <summary>
    /// 清除表过滤器 (谨慎使用，使用后，后续的所有查询将不再受此过滤器影响)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public void ClearTableFilter<T>()
    {
        Context.QueryFilter.Clear<T>();
    }

    public void ClearTableFilter<T, T2>()
    {
        Context.QueryFilter.Clear<T>();
        Context.QueryFilter.Clear<T2>();
    }

    public void ClearTableFilter<T, T2, T3>()
    {
        Context.QueryFilter.Clear<T>();
        Context.QueryFilter.Clear<T2>();
        Context.QueryFilter.Clear<T3>();
    }

    public void ClearTableFilter<T, T2, T3, T4>()
    {
        Context.QueryFilter.Clear<T>();
        Context.QueryFilter.Clear<T2>();
        Context.QueryFilter.Clear<T3>();
        Context.QueryFilter.Clear<T4>();
    }

    public void ClearTableFilter<T, T2, T3, T4, T5>()
    {
        Context.QueryFilter.Clear<T>();
        Context.QueryFilter.Clear<T2>();
        Context.QueryFilter.Clear<T3>();
        Context.QueryFilter.Clear<T4>();
        Context.QueryFilter.Clear<T5>();
    }
    

    public void ClearAllTableFilter()
    {
        Context.QueryFilter.Clear();
    }

    #endregion

    #region 获取Token授权信息

    public VinJwtTokenModel? GetTokenModel()
    {
        return VinSecurityTool.GetTokenModelByToken();
    }

    public T? GetTokenModel<T>() where T : VinJwtTokenModel
    {
        return VinSecurityTool.GetTokenModelByToken<T>();
    }

    #endregion

    #region 查询

    public virtual async Task<List<TEntity>> QueryListAsync(Expression<Func<TEntity, bool>>? whereExpression = null) =>
        whereExpression == null ? await GetListAsync() : await GetListAsync(whereExpression);

    /// <summary>
    /// 根据ID获取实体
    /// </summary>
    public virtual async Task<TEntity> QueryEntityByIdAsync(long? id, string errorMsg = "数据不存在")
    {
        var entity = await base.GetByIdAsync(id);
        if (entity == null) throw new BusinessException(errorMsg);
        return entity;
    }

    /// <summary>
    /// 根据ID获取实体
    /// </summary>
    public virtual async Task<T> QueryEntityByIdAsync<T>(long? id, string errorMsg = "数据不存在")
    {
        return (await QueryEntityByIdAsync(id)).Adapt<T>();
    }

    public virtual async Task<List<TEntity>> QueryByIdsAsync(List<long> ids)
    {
        return await AsQueryable().In(ids).ToListAsync();
    }

    #endregion

    #region 保存或更新

    public override IUpdateable<TEntity> Updateable(TEntity entity, Expression<Func<TEntity, bool>> whereExpression,
        bool ignoreAllNullColumns = true)
    {
        SetOperateInfo(entity);
        return base.Updateable(entity, whereExpression, ignoreAllNullColumns);
    }

    /// <summary>
    /// 设置操作人信息
    /// </summary>
    /// <param name="entity"></param>
    public void SetOperateInfo(TEntity entity)
    {
        var tokenModel = GetTokenModel();
        if (tokenModel != null)
        {
            entity.UpdateUserId = tokenModel.RealUserId;
            entity.UpdateUserName = tokenModel.UserName;
        }

        // if (tokenModel == null)
        // {
        //     entity.Id ??= GetNextId();
        //     return;
        // }
        //
        // if (entity.Id == null)
        // {
        //     entity.Id = GetNextId();
        //     entity.CreateUserId = tokenModel.RealUserId;
        //     entity.CreateUserName = tokenModel.UserName;
        // }
        // else
        // {
        //     entity.UpdateUserId = tokenModel.RealUserId;
        //     entity.UpdateUserName = tokenModel.UserName;
        // }
    }

    /// <summary>
    /// 保存或更新
    /// </summary>
    /// <param name="entity"></param>
    /// <param name="insertCallback"></param>
    /// <param name="updateCallback"></param>
    /// <param name="isIgnoreNull">是否忽略空值</param>
    /// <returns></returns>
    public async Task<TEntity?> SaveOrUpdateAsync(TEntity entity, Func<TEntity, Task>? insertCallback,
        Func<TEntity, Task>? updateCallback = null,
        bool isIgnoreNull = true)
    {
        var tokenModel = GetTokenModel();

        if (!entity.Id.HasValue)
        {
            // 插入
            entity.Id = GetNextId();
            entity.CreateTime ??= DateTime.Now;

            if (insertCallback != null) await insertCallback.Invoke(entity);

            if (tokenModel != null)
            {
                entity.CreateUserId = tokenModel.RealUserId;
                entity.CreateUserName = tokenModel.UserName;
                entity.CreateAccountId = tokenModel.RealAccountId;
                entity.CreateAccountName = tokenModel.AccountName;
            }

            return await AsInsertable(entity).IgnoreColumnsNull(isIgnoreNull).ExecuteCommandAsync() > 0 ? entity : null;
        }

        entity.UpdateTime ??= DateTime.Now;

        if (updateCallback != null) await updateCallback.Invoke(entity);

        if (tokenModel != null)
        {
            entity.UpdateUserId = tokenModel.RealUserId;
            entity.UpdateUserName = tokenModel.UserName;
            entity.UpdateAccountId = tokenModel.RealAccountId;
            entity.UpdateAccountName = tokenModel.AccountName;
        }

        return await AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: isIgnoreNull).ExecuteCommandAsync() > 0
            ? entity
            : null;
    }

    public async Task<TEntity?> SaveOrUpdateAsync(TEntity entity, bool isIgnoreNull = true)
    {
        return await SaveOrUpdateAsync(entity, null, null, isIgnoreNull);
    }

    public async Task<TEntity?> SaveOrUpdateAsync(TEntity entity, Func<SaveType, TEntity, Task>? saveCallback,
        bool isIgnoreNull = true)
    {
        return await SaveOrUpdateAsync(entity,
            async (insertData) =>
            {
                if (saveCallback != null)
                    await saveCallback.Invoke(SaveType.Insert, insertData);
            },
            async (updateData) =>
            {
                if (saveCallback != null)
                    await saveCallback.Invoke(SaveType.Update, updateData);
            }, isIgnoreNull);
    }

    public async Task<bool> InsertRangeAsync(List<TEntity> entities, bool isIgnoreNull)
    {
        var tokenModel = GetTokenModel();
        if (tokenModel != null)
        {
            entities.ForEach(entity =>
            {
                entity.CreateUserId = tokenModel.RealUserId;
                entity.CreateUserName = tokenModel.UserName;
                entity.CreateAccountId = tokenModel.RealAccountId;
                entity.CreateAccountName = tokenModel.AccountName;
            });
        }

        return await AsInsertable(entities).PageSize(1).IgnoreColumnsNull(isIgnoreNull).ExecuteCommandAsync() > 0;
    }

    public async Task<bool> InsertAsync(TEntity entity, bool isIgnoreNull)
    {
        var tokenModel = GetTokenModel();
        if (tokenModel != null)
        {
            entity.CreateUserId = tokenModel.RealUserId;
            entity.CreateUserName = tokenModel.UserName;
            entity.CreateAccountId = tokenModel.RealAccountId;
            entity.CreateAccountName = tokenModel.AccountName;
        }

        return await AsInsertable(entity).IgnoreColumnsNull(isIgnoreNull).ExecuteCommandAsync() > 0;
    }

    #endregion

    #region 删除

    public async Task<bool> LogicDeleteAsync(long? id)
    {
        return await LogicDeleteAsync(m => m.Id == id);
    }

    public async Task<bool> LogicDeleteAsync(IEnumerable<long?> ids)
    {
        return await LogicDeleteAsync(m => ids.Contains(m.Id));
    }

    public async Task<bool> LogicDeleteAsync(IEnumerable<long> ids)
    {
        return await LogicDeleteAsync(m => ids.Contains(m.Id!.Value));
    }

    #endregion

    #region 对比

    public (List<TEntity>, List<TEntity>, List<TEntity>) Compare(
        List<TEntity> newDtoList, List<TEntity> newList)
    {
        // 新增的
        var insertList = newDtoList.Where(m => !m.Id.HasValue).ToList();
        // 更新的
        var updateList = newList.Where(m => newDtoList.Any(n => n.Id == m.Id)).ToList();
        // 删除的
        var deleteList = newList.Where(m => newDtoList.All(n => n.Id != m.Id)).ToList();

        return (insertList, updateList, deleteList);
    }

    public (List<TEntityDto>, List<TEntity>, List<TEntity>) Compare<TEntityDto>(
        List<TEntityDto> newDtoList, List<TEntity> newList)
        where TEntityDto : VinFrameworkBaseEntityDto
    {
        // 新增的
        var insertList = newDtoList.Where(m => !m.Id.HasValue).ToList();
        // 更新的
        var updateList = newList.Where(m => newDtoList.Any(n => n.Id == m.Id)).ToList();
        // 删除的
        var deleteList = newList.Where(m => newDtoList.All(n => n.Id != m.Id)).ToList();

        return (insertList, updateList, deleteList);
    }

    #endregion
}